package tmt.usercenter.web.plugin.filesevice.filecache.ignite;

import com.tmt.fileservice.IFileCache;
import com.tmt.fileservice.exception.FileLoadException;
import lombok.Getter;
import lombok.Setter;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteFileSystem;
import org.apache.ignite.Ignition;
import org.apache.ignite.cache.CacheAtomicityMode;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.FileSystemConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.igfs.IgfsInputStream;
import org.apache.ignite.igfs.IgfsOutputStream;
import org.apache.ignite.igfs.IgfsPath;

import java.io.*;
import java.text.MessageFormat;
import java.util.Map;

/**
 * Created by ThreeManTeam on 2017/5/25.
 */
@Getter
@Setter
public class IgniteFileCache implements IFileCache {

    private Ignite ignite;

    private IgniteFileSystem fileSystem;


    @Override
    public void setConfig(Map<String, String> params) {
        if(params == null)
            return;

        String gridName = params.get("instanceName");
        String fileSystemName = params.get("fileSystemName");

        if (gridName != null && !"".equals(gridName.trim())) {
            IgniteConfiguration ic = new IgniteConfiguration();
            ic.setIgniteInstanceName(gridName);

            if (fileSystemName != null && !"".equals(fileSystemName.trim())) {
                FileSystemConfiguration fileSystemCfg = new FileSystemConfiguration();
                fileSystemCfg.setName(fileSystemName);

                CacheConfiguration cc1 = new CacheConfiguration();
                cc1.setName("myMetaCache");
                cc1.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);

                CacheConfiguration cc2 = new CacheConfiguration();
                cc2.setName("myDataCache");

                fileSystemCfg.setMetaCacheConfiguration(cc1);
                fileSystemCfg.setDataCacheConfiguration(cc2);
                ic.setFileSystemConfiguration(fileSystemCfg);
            }

            ignite = Ignition.getOrStart(ic);
            fileSystem = ignite.fileSystem(fileSystemName);
        }
    }

    @Override
    public void load(String filePath, OutputStream out) throws FileLoadException {
        String rootPath = getIgfsPathString(filePath);
        IgfsPath igfsPath = new IgfsPath(rootPath);
        if (!fileSystem.exists(igfsPath))
            loadFileToCache(filePath, rootPath);

        try(IgfsInputStream igfsIn = fileSystem.open(igfsPath)){
            transferData(igfsIn, out);
        }catch (Exception ex){
            throw new FileLoadException(MessageFormat.format("缓存文件{0}加载异常：{1}", filePath, ex.getMessage()));
        }
    }

    @Override
    public long load(String filePath, long startPos, byte[] data) throws FileLoadException {
        String rootPath = getIgfsPathString(filePath);
        IgfsPath igfsPath = new IgfsPath(rootPath);
        if (!fileSystem.exists(igfsPath))
            loadFileToCache(filePath, rootPath);

        try(IgfsInputStream igfsIn = fileSystem.open(igfsPath)){
            return transferData(igfsIn, startPos,  data);
        }catch (Exception ex){
            throw new FileLoadException(MessageFormat.format("缓存文件{0}加载异常：{1}", filePath, ex.getMessage()));
        }
    }

    @Override
    public void delete(String filePath) {
        String rootPath = getIgfsPathString(filePath);
        IgfsPath igfsPath = new IgfsPath(rootPath);
        if (fileSystem.exists(igfsPath))
            fileSystem.delete(igfsPath, true);
    }

    @Override
    public long getFileSize(String filePath) throws FileLoadException {
        String rootPath = getIgfsPathString(filePath);
        IgfsPath igfsPath = new IgfsPath(rootPath);
        if (!fileSystem.exists(igfsPath))
            loadFileToCache(filePath, rootPath);

        long len = 0L;
        try(IgfsInputStream in = fileSystem.open(igfsPath)){
            len = in.length();
        }catch (Exception ex){}

        return len;
    }

    private String getIgfsPathString(String filePath){
        String[] rootPaths = filePath.split(":");
        return rootPaths.length > 1 ? rootPaths[1] : rootPaths[0];
    }

    private void loadFileToCache(String filePath, String igfsPathInfo ) throws FileLoadException {
        //检测本地文件是否存在。
        File file = new File(filePath);
        if (!file.exists())
            throw new FileLoadException(MessageFormat.format("本地文件{0}不存在", filePath));

        IgfsPath igfsPath = new IgfsPath(igfsPathInfo);
        //创建缓存文件目录。
        if (!fileSystem.exists(igfsPath.parent()))
            fileSystem.mkdirs(igfsPath.parent());

        try(IgfsOutputStream igfsOut  = fileSystem.create(igfsPath, true)){
            try(InputStream in = new FileInputStream(file)) {
                transferData(in, igfsOut);
            }
        }catch (Exception ex){
            throw new FileLoadException(MessageFormat.format("将本地文件{0}加载到缓存时异常：{1}", filePath, ex.getMessage()));
        }
    }

    private void transferData(InputStream in, OutputStream out) throws IOException {
        byte[] bytes = new byte[1024];
        int len = -1;
        while ((len = in.read(bytes)) != -1) {
            out.write(bytes, 0, len);
        }
    }

    private long transferData(InputStream in, long startPos, byte[] data) throws IOException {
        return in.read(data, (int)startPos, data.length);
    }
}
